1   /*
2    * Copyright (C) 2008 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.collect.testing.features;
18  
19  import static com.google.common.truth.Truth.assertThat;
20  
21  import com.google.common.collect.ImmutableSet;
22  import com.google.common.collect.Sets;
23  
24  import junit.framework.TestCase;
25  
26  import java.lang.annotation.Inherited;
27  import java.lang.annotation.Retention;
28  import java.lang.annotation.RetentionPolicy;
29  import java.lang.reflect.Method;
30  import java.util.Collections;
31  import java.util.Set;
32  
33  /**
34   * @author George van den Driessche
35   */
36  // Enum values use constructors with generic varargs.
37  @SuppressWarnings("unchecked")
38  public class FeatureUtilTest extends TestCase {
39    interface ExampleBaseInterface {
40      void behave();
41    }
42  
43    interface ExampleDerivedInterface extends ExampleBaseInterface {
44      void misbehave();
45    }
46  
47    enum ExampleBaseFeature implements Feature<ExampleBaseInterface> {
48      BASE_FEATURE_1,
49      BASE_FEATURE_2;
50  
51      @Override
52      public Set<Feature<? super ExampleBaseInterface>> getImpliedFeatures() {
53        return Collections.emptySet();
54      }
55  
56      @Retention(RetentionPolicy.RUNTIME)
57      @Inherited
58      @TesterAnnotation
59      @interface Require {
60        ExampleBaseFeature[] value() default {};
61        ExampleBaseFeature[] absent() default {};
62      }
63    }
64  
65    enum ExampleDerivedFeature implements Feature<ExampleDerivedInterface>{
66      DERIVED_FEATURE_1,
67      DERIVED_FEATURE_2(ExampleBaseFeature.BASE_FEATURE_1),
68      DERIVED_FEATURE_3,
69  
70      COMPOUND_DERIVED_FEATURE(
71          DERIVED_FEATURE_1,
72          DERIVED_FEATURE_2,
73          ExampleBaseFeature.BASE_FEATURE_2);
74  
75      private Set<Feature<? super ExampleDerivedInterface>> implied;
76  
77      ExampleDerivedFeature(
78          Feature<? super ExampleDerivedInterface> ... implied) {
79        this.implied = ImmutableSet.copyOf(implied);
80      }
81  
82      @Override
83      public Set<Feature<? super ExampleDerivedInterface>> getImpliedFeatures() {
84        return implied;
85      }
86  
87      @Retention(RetentionPolicy.RUNTIME)
88      @Inherited
89      @TesterAnnotation
90      @interface Require {
91        ExampleDerivedFeature[] value() default {};
92        ExampleDerivedFeature[] absent() default {};
93      }
94    }
95  
96    @Retention(RetentionPolicy.RUNTIME)
97    @interface NonTesterAnnotation {
98    }
99  
100   @ExampleBaseFeature.Require({ExampleBaseFeature.BASE_FEATURE_1})
101   private static abstract class ExampleBaseInterfaceTester extends TestCase {
102     protected final void doNotActuallyRunThis() {
103       fail("Nobody's meant to actually run this!");
104     }
105   }
106 
107   @NonTesterAnnotation
108   @ExampleDerivedFeature.Require({ExampleDerivedFeature.DERIVED_FEATURE_2})
109   private static class ExampleDerivedInterfaceTester
110       extends ExampleBaseInterfaceTester {
111     // Exists to test that our framework doesn't run it:
112     @SuppressWarnings("unused")
113     @ExampleDerivedFeature.Require({
114         ExampleDerivedFeature.DERIVED_FEATURE_1,
115         ExampleDerivedFeature.DERIVED_FEATURE_2})
116     public void testRequiringTwoExplicitDerivedFeatures() throws Exception {
117       doNotActuallyRunThis();
118     }
119 
120     // Exists to test that our framework doesn't run it:
121     @SuppressWarnings("unused")
122     @ExampleDerivedFeature.Require({
123         ExampleDerivedFeature.DERIVED_FEATURE_1,
124         ExampleDerivedFeature.DERIVED_FEATURE_3})
125     public void testRequiringAllThreeDerivedFeatures() {
126       doNotActuallyRunThis();
127     }
128 
129     // Exists to test that our framework doesn't run it:
130     @SuppressWarnings("unused")
131     @ExampleBaseFeature.Require(absent = {ExampleBaseFeature.BASE_FEATURE_1})
132     public void testRequiringConflictingFeatures() throws Exception {
133       doNotActuallyRunThis();
134     }
135   }
136 
137   @ExampleDerivedFeature.Require(
138       absent = {ExampleDerivedFeature.DERIVED_FEATURE_2})
139   private static class ExampleDerivedInterfaceTester_Conflict
140       extends ExampleBaseInterfaceTester {
141   }
142 
143   public void testTestFeatureEnums() throws Exception {
144     // Haha! Let's test our own test rig!
145     FeatureEnumTest.assertGoodFeatureEnum(
146         FeatureUtilTest.ExampleBaseFeature.class);
147     FeatureEnumTest.assertGoodFeatureEnum(
148         FeatureUtilTest.ExampleDerivedFeature.class);
149   }
150 
151   public void testAddImpliedFeatures_returnsSameSetInstance() throws Exception {
152     Set<Feature<?>> features = Sets.<Feature<?>>newHashSet(
153         ExampleBaseFeature.BASE_FEATURE_1);
154     assertSame(features, FeatureUtil.addImpliedFeatures(features));
155   }
156 
157   public void testAddImpliedFeatures_addsImpliedFeatures() throws Exception {
158     Set<Feature<?>> features;
159 
160     features = Sets.<Feature<?>>newHashSet(
161         ExampleDerivedFeature.DERIVED_FEATURE_1);
162     assertThat(FeatureUtil.addImpliedFeatures(features)).has().item(
163         ExampleDerivedFeature.DERIVED_FEATURE_1);
164 
165     features = Sets.<Feature<?>>newHashSet(
166         ExampleDerivedFeature.DERIVED_FEATURE_2);
167     assertThat(FeatureUtil.addImpliedFeatures(features)).has().exactly(
168         ExampleDerivedFeature.DERIVED_FEATURE_2,
169         ExampleBaseFeature.BASE_FEATURE_1);
170 
171     features = Sets.<Feature<?>>newHashSet(
172         ExampleDerivedFeature.COMPOUND_DERIVED_FEATURE);
173     assertThat(FeatureUtil.addImpliedFeatures(features)).has().exactly(
174         ExampleDerivedFeature.COMPOUND_DERIVED_FEATURE,
175         ExampleDerivedFeature.DERIVED_FEATURE_1,
176         ExampleDerivedFeature.DERIVED_FEATURE_2,
177         ExampleBaseFeature.BASE_FEATURE_1,
178         ExampleBaseFeature.BASE_FEATURE_2);
179   }
180 
181   public void testImpliedFeatures_returnsNewSetInstance() throws Exception {
182     Set<Feature<?>> features = Sets.<Feature<?>>newHashSet(
183         ExampleBaseFeature.BASE_FEATURE_1);
184     assertNotSame(features, FeatureUtil.impliedFeatures(features));
185   }
186 
187   public void testImpliedFeatures_returnsImpliedFeatures() throws Exception {
188     Set<Feature<?>> features;
189 
190     features = Sets.<Feature<?>>newHashSet(
191         ExampleDerivedFeature.DERIVED_FEATURE_1);
192     assertTrue(FeatureUtil.impliedFeatures(features).isEmpty());
193 
194     features = Sets.<Feature<?>>newHashSet(
195         ExampleDerivedFeature.DERIVED_FEATURE_2);
196     assertThat(FeatureUtil.impliedFeatures(features)).has().item(
197         ExampleBaseFeature.BASE_FEATURE_1);
198 
199     features = Sets.<Feature<?>>newHashSet(
200         ExampleDerivedFeature.COMPOUND_DERIVED_FEATURE);
201     assertThat(FeatureUtil.impliedFeatures(features)).has().exactly(
202         ExampleDerivedFeature.DERIVED_FEATURE_1,
203         ExampleDerivedFeature.DERIVED_FEATURE_2,
204         ExampleBaseFeature.BASE_FEATURE_1,
205         ExampleBaseFeature.BASE_FEATURE_2);
206   }
207 
208   public void testBuildTesterRequirements_class() throws Exception {
209     assertEquals(FeatureUtil.buildTesterRequirements(
210             ExampleBaseInterfaceTester.class),
211         new TesterRequirements(
212             Sets.<Feature<?>>newHashSet(ExampleBaseFeature.BASE_FEATURE_1),
213             Collections.<Feature<?>>emptySet()));
214 
215     assertEquals(FeatureUtil.buildTesterRequirements(
216             ExampleDerivedInterfaceTester.class),
217         new TesterRequirements(
218             Sets.<Feature<?>>newHashSet(
219                 ExampleBaseFeature.BASE_FEATURE_1,
220                 ExampleDerivedFeature.DERIVED_FEATURE_2),
221             Collections.<Feature<?>>emptySet()));
222   }
223 
224   public void testBuildTesterRequirements_method() throws Exception {
225     assertEquals(FeatureUtil.buildTesterRequirements(
226         ExampleDerivedInterfaceTester.class.getMethod(
227             "testRequiringTwoExplicitDerivedFeatures")),
228         new TesterRequirements(
229             Sets.<Feature<?>>newHashSet(
230                 ExampleBaseFeature.BASE_FEATURE_1,
231                 ExampleDerivedFeature.DERIVED_FEATURE_1,
232                 ExampleDerivedFeature.DERIVED_FEATURE_2),
233             Collections.<Feature<?>>emptySet()));
234     assertEquals(FeatureUtil.buildTesterRequirements(
235         ExampleDerivedInterfaceTester.class.getMethod(
236             "testRequiringAllThreeDerivedFeatures")),
237         new TesterRequirements(
238             Sets.<Feature<?>>newHashSet(
239                 ExampleBaseFeature.BASE_FEATURE_1,
240                 ExampleDerivedFeature.DERIVED_FEATURE_1,
241                 ExampleDerivedFeature.DERIVED_FEATURE_2,
242                 ExampleDerivedFeature.DERIVED_FEATURE_3),
243             Collections.<Feature<?>>emptySet()));
244   }
245 
246   public void testBuildTesterRequirements_classClassConflict()
247       throws Exception {
248     try {
249       FeatureUtil.buildTesterRequirements(
250           ExampleDerivedInterfaceTester_Conflict.class);
251       fail("Expected ConflictingRequirementsException");
252     } catch (ConflictingRequirementsException e) {
253       assertThat(e.getConflicts()).has().item(
254           ExampleBaseFeature.BASE_FEATURE_1);
255       assertEquals(ExampleDerivedInterfaceTester_Conflict.class, e.getSource());
256     }
257   }
258 
259   public void testBuildTesterRequirements_methodClassConflict()
260       throws Exception {
261     final Method method = ExampleDerivedInterfaceTester.class
262         .getMethod("testRequiringConflictingFeatures");
263     try {
264       FeatureUtil.buildTesterRequirements(method);
265       fail("Expected ConflictingRequirementsException");
266     } catch (ConflictingRequirementsException e) {
267       assertThat(e.getConflicts()).has().item(
268           ExampleBaseFeature.BASE_FEATURE_1);
269       assertEquals(method, e.getSource());
270     }
271   }
272 
273   public void testBuildDeclaredTesterRequirements() throws Exception {
274     assertEquals(FeatureUtil.buildDeclaredTesterRequirements(
275         ExampleDerivedInterfaceTester.class
276             .getMethod("testRequiringTwoExplicitDerivedFeatures")),
277         new TesterRequirements(FeatureUtil.addImpliedFeatures(
278             Sets.<Feature<?>>newHashSet(
279                 ExampleDerivedFeature.DERIVED_FEATURE_1,
280                 ExampleDerivedFeature.DERIVED_FEATURE_2)),
281             Collections.<Feature<?>>emptySet()));
282   }
283 
284 }